#ifndef VROUTE_ADAPTER_HPP_3
#define VROUTE_ADAPTER_HPP_3
#include "vrouteDefines.h"

#if defined(__cplusplus)|defined(c_plusplus)
extern "C"{
#endif

//to start the client core
int vroute_start();

//to stop the client core and dispose all resource
int vroute_stop();

///get a global unique port from stack
int vroute_getAPort(int timeout);
int vroute_getAPortSync(getPortCallback gcb);

///regist a port to global stack
int vroute_registPort(int port, int timeout);
int vroute_registPortSync(int port, registPortCallback rgcb);

///set the port closing callback function
int vroute_setPortClosingCallback(int port, portClosingCallback pccb);
portClosingCallback vroute_getPortClosingCallback(int port);

int vroute_setPortClosingCallbackVid(vroute_t vid, portClosingCallback pccb);
portClosingCallback vroute_getPortClosingCallbackVid(vroute_t vid);

/************************************************************************
 * regist port to core part
 * if want to create a port use fixedpath or auto path will call this method
 * also call this method to create listen port
 * @param port: regist port, notice the port shuld be unqiue in the system, other will failed
 * @param flag: regist type, one of LISTENPORT, PATHPORT, SendToPort
 * @return -1 falied
 * ***********************************************************************/
vroute_t vroute_bind(int port, int timeout);

/*************************************************************************
 * regist port to core use async style, if regist finished the core will call bscb method
 * @param bscb: call back method
 * @return E_OPERATION_NOBLOCK if sucess, other failed
 * ************************************************************************/
int vroute_bind_sync(int port, bindSyncCallback bscb);

/*************************************************************************
 * if want to let vid cam listen connect from others, must call this method to set the port listenable
 * the vid must be the result of bind with argument LISTENPORT as type
 * @param vid: listen port vid, must be result of bind use LISTENPORT as argument type
 * @param count: max count of port can be listen by vid
 * @return E_TRANC_SUCESS if sucess
 * ************************************************************************/
int vroute_listen(vroute_t vid, int count);

/**************************************************************************
 * after call listen, the vid is listenable, so it can accept connection passed in
 * notice: must use the vid which listen sucess
 * @param vid: the accept vid, must be call listen first
 * @param timeout: set timeout value, set timeout <=0 will nerver timeout
 * @return if timeout, return E_TIMEOUT, if sucess E_TRANC_SUCESS
 * **************************************************************************/
int vroute_accept(vroute_t vid, int timeout);

/************************************************************************
 * accept connection use async style, notice ascb must not be null
 * @param ascb: accept callback funtion, if null, will ocurr error
 * @return E_CALLBACK_NULL, if not set the callback function; VID_NOT_EXIST, if vid is invalidate, else E_TRANC_SUCESS
 * ***********************************************************************/
int vroute_accept_sync(vroute_t vid, acceptSyncCallback ascb);

/****************************************************************
 * recv will block until data avaliable, notice the vid must be get from accept
 * if vid is not got from accept, will occure error
 * @param vid: the receive vid, must got from accept, or ocurr error
 * @param flag: 0 or RECEIVE_FLAG_NONBLOCK
 * @param buffer: buffer to store the received data
 * @param bufferLen: the buffer length
 * @return <0 failed, 0 no such vid, or data length
 * ****************************************************************/
int vroute_recv(vroute_t vid, int flag, void* buffer, int bufferLen, int timeout);

/*****************************************************************
 * use no block style to receive data, if rscb null will ocurr error
 * the vid must be got from accept
 * @param rscb: receive callback, notice must call getData in callback to get data
 * @return E_OPERATION_NOBLOCK
 * ****************************************************************/
int vroute_recv_sync(vroute_t vid, recvSyncCallback rscb);

/*****************************************************************
 * this method may be block untill write data to buffer finished, if flag is set to SEND_FLAG_NONBLOCK will not block
 * should avolid send a big block once a time
 * @param vid: the send Id, must be got from accept, or will ocure error
 * @param flag: 0 or SEND_FLAG_NONBLICK
 * @param buffer: the content to sendout
 * @param bufferLen: the content length
 * @return E_OPERATION_NOBLOCK is flag set to nonblock, >=0 bytes send, or error
 * *****************************************************************/
int vroute_send(vroute_t vid, int flag, const void* buffer, int bufferLen, int timeout);

/**********************************************************************
 * use unblock style to call send, when write to buffer finished, return if enough space
 * before callback the buffer can not be free
 * @param buffer: sscb, callback function when write finished
 * @param flag: 0 or SEND_FLAG_NONBLICK
 * @return if sucess E_OPERATION_NOBLOCK, else error
 * *********************************************************************/
int vroute_send_sync(vroute_t vid, int flag, const void* buffer, int bufferLen, sendSyncCallback sscb);

/***********************************************************************
 * use block way to send packet, if flag set NONBLOCK, then will ignore left data
 * @param  target: send to target node, address, port
 * @param  flag: 0 or SEND_FLAG_NONBLICK or set path
 * @return  E_OPERATION_NOBLOCK if set flag to SEND_FLAG_NONBLICK, or the bytes send
 * *********************************************************************/
int vroute_sendTo(int localPort, const EndPoint* target, int flag, const void* buffer, int bufferLen, int timeout);

/***********************************************************************
 * use unblock way to send packet, if stscb NULL failed, this way will send all data to stack
 * @param  stscb: sendTo callback funtion.
 * @param  flag: 0 or SEND_FLAG_NONBLICK or set path
 * @return if sucess E_OPERATION_NOBLOCK, else error
 * *********************************************************************/
int vroute_sendTo_sync(int localPort, const EndPoint* target, int flag, const void* buffer, int bufferLen, sendToSyncCallback stscb);

/************************************************************************
 * get data from local port, if no data avaliable will block untill some data come in, if flag set to nonblock, will return immedatly
 * @param  localPort: local listen port
 * @param  flag: 0 or RECEIVE_FLAG_NONBLOCK
 * @return  E_OPERATION_NOBLOCK if set nonblock, or bytes receivefrom, or error
 * **********************************************************************/
int vroute_receiveFrom(int localPort, int flag, void* buffer, int bufferLen, int timeout);

/*************************************************************************
 * receive from data from local port, use nonblock style, when data avaliable, will call the callback method
 * @param  rfscb: callback function, notice must call getData in this function to get data
 * @return  E_OPERATION_NOBLOCK if sucess, of failed
 * ************************************************************************/
int vroute_receiveFrom_sync(int localPort, receiveFromSyncCallback rfscb);

/***************************************************************************
 * get data from memory, call this method in recevie callback
 * @param  port: the parameter of receive callback.
 * @param  buffer: the buffer to hold the data content
 * @param  len: the buffer length
 * @return  data length got, or error
 * ************************************************************************/
int vroute_getData(int port, char* buffer, int len);

/*************************************************************************
 * close the vid get from accept or bind
 * nitice always close implact, so sys can close port immediately
 * @param  vid: the vid to close
 * @return  VID_NOT_EXIST, or E_TRANC_SUCESS
 * ************************************************************************/
int vroute_close(vroute_t vid);

/****************************************************************************
 * recevefrom will regist a port, if receivefrom not return get port failed, then should close the port explicit
 * @param  port: close port
 * @return  PORT_NOT_EXIST, or E_TRANC_SUCESS
 * ***************************************************************************/
int vroute_closePort(int port);

/*****************************************************************************
 * get loocal address
 * @return  local address
 * ***************************************************************************/
int vroute_getLocalAddr(NodeAddr* nodeAddr);

/*****************************************************************************
 * get vid releate remote address
 * @return  remote address
 * ****************************************************************************/
int vroute_getRemoteAddr(vroute_t vid, NodeAddr* nodeAddr);

/******************************************************************************
 * use boardcast way to get the path nodevalues to reach target
 * @param tracertType: set flag to tracert or rollback 0 OR TRACERT_FLAG_ROOLBACK 
 * @param timeout: set timeout value, set timeout <=0 will nerver timeout 
 * @param  target: tracert to target
 * @param nodeList: get the tarcert path nodeAddr list
 * @param nodeCount: the NodeAddr count
 * @return  E_TIMEOUT or failed, or E_TRAC_SUCESS;
 * *****************************************************************************/
int vroute_tracertTarget(int port, int tracertType, const NodeAddr* target, NodeAddr* nodeList, int nodeCount, int timeout);

/*******************************************************************************
 * tracert use nonblock way, when tracert finished or timeout, will call callback immediately
 * @param  ttcb: tracert callback function
 * @return  E_OPERATION_NOBLOCK if sucess.
 * *****************************************************************************/
int vroute_tracertTarget_sync(int port, int tracertType, const NodeAddr* target, tarcertTargetCallback ttcb);

/***********************************************************************************
 * query target device use given type the value set to value and set the length
 * @param type: query value type
 * @param  valuelen: the value length
 * @param  value: the query value
 * @param timeout: set timeout value, set timeout <=0 will nerver timeout
 * @param  result: query result
 * @return  E_TIMEOUT or E_TRANC_SUCESS, or E_NO_SUCHDEVICE
 * **********************************************************************************/
int vroute_queryTarget(int port, int type, int valueLength, void* value, deviceInfo* result, int timeout);

/**************************************************************************************
 * use no block style to get target device info
 * @param  qtcb: querydevice callback
 * **************************************************************************************/
int vroute_queryTarget_sync(int port, int type, int valueLength, void* value, queryTargetCallback qtcb);

/*****************************************************************************************
 * use given path type to check target can be reached
 * @param timeout: set timeout value, set timeout <=0 will nerver timeout
 * @return E_TIMEOUT or E_TRANC_SUCESS, or E_DEVICE_UNREACHABLE;
 * ***************************************************************************************/
int vroute_targetReachAble(int port, const NodeAddr* target, int timeout);

/******************************************************************************************
 * use nonblock way to check reachable
 * @param  tracb: tracert reachable callback
 * @return E_OPERATION_NOBLOCK if sucess, else error
 * *****************************************************************************************/
int vroute_targetReachAble_sync(int port, const NodeAddr* target, targetReachAbleCallback tracb);

/*******************************************************************************************
 * sendTo funtion can bind a port first then set the fixedPath or call get autoPath method,
 * so that can pass packet more effective
 * @param  nodeList: the fixedNodeList to set
 * @param  nodeCount: the node count
 * @return  E_TRANC_SUCESS if sucess, else error
 * *****************************************************************************************/
int vroute_setFixedNodeList(const NodeAddr* target, const NodeAddr* nodeList, int nodeCount);


int vroute_getVroutePort(vroute_t vid);

/*******************************************************************************************
 * get error code string 
 * *****************************************************************************************/
int vroute_getErrorInfo(int errorCode, char* buffer, int bufferLen);

////////////////////////////////////////////////////
/// connect to other end
/// if localPort <=0 or exist already will not occure a error, just get another port instead
////////////////////////////////////////////////////
vroute_t vroute_connect(const EndPoint* target, int timeout, int localPort);

int vroute_connect_sync(const EndPoint* target, connectCallback ccb, int localPort);

int vroute_isPortAlreadyExist(int port);

#if defined(__cplusplus)|defined(c_plusplus)
}
#endif
#endif //VROUTE_ADAPTER_HPP_3
